//
// Created by lester on 2023/12/21.
//

#ifndef TEST_LOGGER_H
#define TEST_LOGGER_H
#include <utility>

#include "TimeStamp.h"
#include "GetThreadId.h"
enum class Level{
    INFO,
    WARN,
    DEBUG,
    TRACE,
    ERROR,
    SYS_ERROR
};
void defaultFlush(const char* buffer,size_t size){
    fwrite(buffer,1,size,stdout);
}
class Logger{
    static std::map<Level,std::string> level2string;
    static std::map<std::string,Level> string2level;
public:
    Logger(Level level,int line,const std::string& fileName,const std::string& funcName){
        g_output_func = defaultFlush;
        std::string stringTime = TimeStamp::Now().Format();
        stream << stringTime <<" ";
        stream << util::GetThreadId() << " ";
        stream << level2string[level] <<" ";
        stream << fileName << " ";
        stream << funcName << ":";
        stream << line << " ";
    }
    static Level g_log_level;
    std::function<void(const char* data,size_t size)> g_output_func;
    void SetOutputFunc(std::function<void(const char* data,size_t size)> outputFunc);
    OutputStream& Stream(){
        return stream;
    }
    ~Logger() {
        g_output_func(stream.buffer_.begin(),stream.buffer_.Cur() - stream.buffer_.begin());
    }
private:
    OutputStream stream;
};
std::map<Level,std::string> Logger::level2string  = {
        {Level::INFO,"INFO"},
        {Level::WARN,"WARN"},
        {Level::DEBUG,"DEBUG"},
        {Level::TRACE,"TRACE"},
        {Level::ERROR,"ERROR"},
        {Level::SYS_ERROR,"SYS_ERROR"}};

void Logger::SetOutputFunc(std::function<void(const char *, size_t)> outputFunc) {
    g_output_func = std::move(outputFunc);
}

#define log_info  (Logger(Level::INFO,__LINE__,__FILE__,__func__ ).Stream())
#define log_debug (Logger(Level::DEBUG,__LINE__,__FILE__,__func__ ).Stream())
#define log_warn  (Logger(Level::INFO,__LINE__,__FILE__,__func__ ).Stream())
#define log_error (Logger(Level::ERROR,__LINE__,__FILE__,__func__ ).Stream())
#define log_fatal (Logger(Level::FATAL,__LINE__,__FILE__,__func__ ).Stream())
#define log_trace (Logger(Level::TRACE,__LINE__,__FILE__,__func__ ).Stream())
#endif //TEST_LOGGER_H
